package org.jsola.hr.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.jsola.admin.dto.DictItemUpdateDTO;
import org.jsola.admin.entity.AreaDO;
import org.jsola.admin.entity.DictItemDO;
import org.jsola.common.DateKit8;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.DateUtils;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.EmpSocStatus;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IEmpSocRelatedDAO;
import org.jsola.hr.dto.EmpSocRelatedAddDTO;
import org.jsola.hr.dto.EmpSocRelatedUpdateDTO;
import org.jsola.hr.dto.excel.EmpImportSocItemRelatedDTO;
import org.jsola.hr.dto.excel.EmpImportSocRelatedDTO;
import org.jsola.hr.dto.excel.EmpInfoImportDTO;
import org.jsola.hr.entity.*;
import org.jsola.hr.provider.IAdminProviderService;
import org.jsola.hr.query.EmpSocRelatedQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.EmpSocRelatedListVO;
import org.jsola.hr.vo.EmpSocRelatedVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

import static org.jsola.hr.constant.EmpSocConstant.*;
import static org.jsola.hr.constant.HrConstants.*;

/**
 * 员工社保相关信息表
 *
 * @author zhr
 */
@Service("hrEmpSocRelatedServiceImpl")
public class EmpSocRelatedServiceImpl implements IEmpSocRelatedService {

    @Autowired
    private IEmpSocRelatedDAO empSocRelatedDAO;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private IEmpSocInfoService empSocInfoService;

    @Autowired
    private IEmpSocItemService empSocItemService;

    @Autowired
    private ISocProgService socProgService;

    @Autowired
    @Lazy
    private IAdminProviderService adminProviderService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public EmpSocRelatedVO save(EmpSocRelatedAddDTO empSocRelatedAddDTO, TokenUser tokenUser) {
        // 转DO
        EmpSocRelatedDO empSocRelatedDO = empSocRelatedAddDTO.to(EmpSocRelatedDO.class);
        // 保存
        empSocRelatedDO = save(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return empSocRelatedDO.to(EmpSocRelatedVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(EmpSocRelatedUpdateDTO empSocRelatedUpdateDTO, TokenUser tokenUser) {
        //转DO
        EmpSocRelatedDO empSocRelatedDO = empSocRelatedUpdateDTO.to(EmpSocRelatedDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... empSocRelatedIds) {
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) empSocRelatedIds);
    }


    @Override
    public EmpSocRelatedVO selectById(String empSocRelatedId, String siteId) {
        EmpSocRelatedDO empSocRelatedDO = selectDOById(empSocRelatedId, siteId);
        if (empSocRelatedDO == null) {
            return null;
        }
        return empSocRelatedDO.to(EmpSocRelatedVO.class);
    }

    @Override
    public List<EmpSocRelatedListVO> select(EmpSocRelatedQuery empSocRelatedQuery, String siteId) {
        List<EmpSocRelatedDO> empSocRelatedDOList = selectDO(empSocRelatedQuery, siteId);
        if (CollectionUtils.isEmpty(empSocRelatedDOList)) {
            return empSocRelatedDOList == null ? null : new ArrayList<>();
        }
        return empSocRelatedDOList.stream()
                .map(empSocRelatedDO -> empSocRelatedDO.to(EmpSocRelatedListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(EmpSocRelatedQuery empSocRelatedQuery, String siteId) {
        Example example = buildExample(empSocRelatedQuery, siteId);
        return empSocRelatedDAO.selectCountByExample(example);
    }

    @Override
    public Page<EmpSocRelatedListVO> selectPage(EmpSocRelatedQuery empSocRelatedQuery, String siteId) {
        Example example = buildExample(empSocRelatedQuery, siteId);
        Page<EmpSocRelatedDO> page = empSocRelatedDAO.selectPageByExample(example,
                empSocRelatedQuery.getPageNo(),
                empSocRelatedQuery.getPageSize());

        return page.to(EmpSocRelatedListVO.class);
    }

    @Override
    public EmpSocRelatedDO selectDOById(String empSocRelatedId, String siteId) {
        return listById(empSocRelatedId, siteId);
    }

    @Override
    public List<EmpSocRelatedDO> selectDO(EmpSocRelatedQuery empSocRelatedQuery, String siteId) {
        Example example = buildExample(empSocRelatedQuery, siteId);
        return empSocRelatedDAO.selectByExample(example);
    }

    @Override
    public List<EmpSocRelatedDO> selectByEmpIdList(List<String> empIdList, String siteId) {
        Example example = new Example(EmpSocRelatedDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("empId", empIdList);
        return empSocRelatedDAO.selectByExample(example);
    }

    @Override
    public List<EmpSocRelatedDO> selectByEmpIdListSelectProperties(List<String> empIdList, String siteId) {
        Example example = new Example(EmpSocRelatedDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("empId", empIdList);
        example.selectProperties("id", "empId");
        return empSocRelatedDAO.selectByExample(example);
    }

    @Override
    public EmpSocRelatedDO selectByEmpId(String empId, String siteId) {
        Example example = new Example(EmpSocRelatedDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("empId", empId);
        return empSocRelatedDAO.selectOneByExample(example);
    }

    @Override
    public EmpSocRelatedDO selectByEmpIdIgnoreValid(String empId, String siteId) {
        Example example = new Example(EmpSocRelatedDO.class);
        example.and()
                .andEqualTo("siteId", siteId)
                .andEqualTo("empId", empId);
        return empSocRelatedDAO.selectOneByExample(example);
    }

    @Override
    public void updatePlanDateByIncreaseMsg(Integer type, EmpSocRelatedDO empSocRelatedDO,
                                            Date planIncreaseDate, String schemeId, TokenUser tokenUser) {
        empSocRelatedDO.setSchemeId(schemeId);
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocPlanIncreaseDate(planIncreaseDate);
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfPlanIncreaseDate(planIncreaseDate);
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMePlanIncreaseDate(planIncreaseDate);
        } else {
            throw new ParamException("参保方案类型错误");
        }
        updateByIdSelective(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    public void setIncreaseDateByType(Integer type, EmpSocRelatedDO empSocRelatedDO, Date increaseDat) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocIncreaseDate(increaseDat);
            empSocRelatedDO.setSocState(EmpSocStatus.INCREMENT.getValue());
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfIncreaseDate(increaseDat);
            empSocRelatedDO.setPfState(EmpSocStatus.INCREMENT.getValue());
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMeIncreaseDate(increaseDat);
            empSocRelatedDO.setMeState(EmpSocStatus.INCREMENT.getValue());
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    public void setPlanIncreaseDateByType(Integer type, EmpSocRelatedDO empSocRelatedDO, Date increaseDat) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocPlanIncreaseDate(increaseDat);
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfPlanIncreaseDate(increaseDat);
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMePlanIncreaseDate(increaseDat);
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    public void updateIncreaseDate(EmpSocRelatedDO empSocRelatedDO, Integer type, Boolean plan, TokenUser tokenUser) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocIncreaseDate(empSocRelatedDO.getSocPlanIncreaseDate());
            empSocRelatedDO.setSocPlanIncreaseDate(null);
            if (plan) {
                empSocRelatedDO.setSocState(EmpSocStatus.WAIT_INCREMENT.getValue());
            } else {
                empSocRelatedDO.setSocState(EmpSocStatus.INCREMENT.getValue());
            }
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfIncreaseDate(empSocRelatedDO.getPfPlanIncreaseDate());
            empSocRelatedDO.setPfPlanIncreaseDate(null);
            if (plan) {
                empSocRelatedDO.setPfState(EmpSocStatus.WAIT_INCREMENT.getValue());
            } else {
                empSocRelatedDO.setPfState(EmpSocStatus.INCREMENT.getValue());
            }
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMeIncreaseDate(empSocRelatedDO.getMePlanIncreaseDate());
            empSocRelatedDO.setMePlanIncreaseDate(null);
            if (plan) {
                empSocRelatedDO.setMeState(EmpSocStatus.WAIT_INCREMENT.getValue());
            } else {
                empSocRelatedDO.setMeState(EmpSocStatus.INCREMENT.getValue());
            }
        } else {
            throw new ParamException("参保方案类型错误");
        }
        updateById(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    public void updateDecreaseDate(EmpSocRelatedDO empSocRelatedDO, Integer type, Boolean plan, TokenUser tokenUser) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocStopDate(empSocRelatedDO.getSocPlanStopDate());
            empSocRelatedDO.setSocPlanStopDate(null);
            if (plan) {
                empSocRelatedDO.setSocState(EmpSocStatus.WAIT_ATTRITION.getValue());
            } else {
                empSocRelatedDO.setSocState(EmpSocStatus.ATTRITION.getValue());
            }
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfSealedDate(empSocRelatedDO.getPfPlanSealedDate());
            empSocRelatedDO.setPfPlanSealedDate(null);
            if (plan) {
                empSocRelatedDO.setPfState(EmpSocStatus.WAIT_ATTRITION.getValue());
            } else {
                empSocRelatedDO.setPfState(EmpSocStatus.ATTRITION.getValue());
            }
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMeStopDate(empSocRelatedDO.getMePlanStopDate());
            empSocRelatedDO.setMePlanStopDate(null);
            if (plan) {
                empSocRelatedDO.setMeState(EmpSocStatus.WAIT_ATTRITION.getValue());
            } else {
                empSocRelatedDO.setMeState(EmpSocStatus.ATTRITION.getValue());
            }
        } else {
            throw new ParamException("参保方案类型错误");
        }
        updateById(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    public void updateNormalStatus(EmpSocRelatedDO empSocRelatedDO, Integer type, TokenUser tokenUser) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocState(EmpSocStatus.NORMAL_SOC.getValue());
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfState(EmpSocStatus.NORMAL_SOC.getValue());
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMeState(EmpSocStatus.NORMAL_SOC.getValue());
        } else {
            throw new ParamException("参保方案类型错误");
        }
        empSocRelatedDAO.updateByPrimaryKeySelective(empSocRelatedDO);
    }

    @Override
    public void setNormalStatus(EmpSocRelatedDO empSocRelatedDO, Integer type, TokenUser tokenUser) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocState(EmpSocStatus.NORMAL_SOC.getValue());
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfState(EmpSocStatus.NORMAL_SOC.getValue());
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMeState(EmpSocStatus.NORMAL_SOC.getValue());
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    public void updateStopStatus(EmpSocRelatedDO empSocRelatedDO, Integer type, TokenUser tokenUser) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocState(EmpSocStatus.STOP_SOC.getValue());
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfState(EmpSocStatus.STOP_SOC.getValue());
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMeState(EmpSocStatus.STOP_SOC.getValue());
        } else {
            throw new ParamException("参保方案类型错误");
        }
        empSocRelatedDAO.updateByPrimaryKeySelective(empSocRelatedDO);
    }

    @Override
    public void updatePlanDateByDecreaseMsg(EmpSocRelatedDO empSocRelatedDO, Integer type, Date decreaseDate) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocPlanStopDate(decreaseDate);
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfPlanSealedDate(decreaseDate);
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMePlanStopDate(decreaseDate);
        } else {
            throw new ParamException("参保方案类型错误");
        }

    }

    @Override
    public void setStopDateByType(EmpSocRelatedDO empSocRelatedDO, Integer type, Date decreaseDate) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocStopDate(decreaseDate);
            empSocRelatedDO.setSocState(EmpSocStatus.ATTRITION.getValue());
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfSealedDate(decreaseDate);
            empSocRelatedDO.setPfState(EmpSocStatus.ATTRITION.getValue());
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMeStopDate(decreaseDate);
            empSocRelatedDO.setMeState(EmpSocStatus.ATTRITION.getValue());
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    public void setStopDateByType2(EmpSocRelatedDO empSocRelatedDO, Integer type, Date decreaseDate) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setSocPlanStopDate(decreaseDate);
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setPfPlanSealedDate(decreaseDate);
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelatedDO.setMePlanStopDate(decreaseDate);
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void initAllRelatedByCompany(String companyId, TokenUser tokenUser) {
        System.out.println(System.currentTimeMillis());
        List<EmpInfoDO> empInfoList = empInfoService.selectEmpByCompanyId(companyId, tokenUser);
        System.out.println(System.currentTimeMillis());
        if (!CollectionUtils.isEmpty(empInfoList)) {
            List<String> empIdList = empInfoList.stream().map(EmpInfoDO::getId).collect(Collectors.toList());
            List<EmpSocRelatedDO> empSocRelatedList = selectByEmpIdListSelectProperties(empIdList, tokenUser.getSiteId());
            System.out.println(System.currentTimeMillis());
            List<String> relatedEmpIdList = empSocRelatedList.stream().map(EmpSocRelatedDO::getEmpId).collect(Collectors.toList());
            empIdList.removeAll(relatedEmpIdList);
            System.out.println(System.currentTimeMillis());
            if (!CollectionUtils.isEmpty(empIdList)) {
                List<EmpSocRelatedDO> insertList = new ArrayList<>();
                for (String empId : empIdList) {
                    EmpSocRelatedDO insertDO = new EmpSocRelatedDO();
                    insertDO.setEmpId(empId);
                    insertDO.setCompanyId(companyId);
                    insertDO.setSocState(0);
                    insertDO.setMeState(0);
                    insertDO.setPfState(0);
                    insertDO.preInsert(tokenUser.getUserId());
                    insertDO.setCreateUserId(tokenUser.getUserId());
                    insertDO.setGmtCreate(new Date());
                    insertDO.setModifiedUserId(tokenUser.getUserId());
                    insertDO.setGmtModified(new Date());
                    insertDO.setSiteId(tokenUser.getSiteId());
                    insertList.add(insertDO);
                }
                if (!CollectionUtils.isEmpty(insertList)) {
                    empSocRelatedDAO.insertListAndSetId(insertList);
                }
            }
        }
    }

    @Override
    public void initRelatedByEmpId(String empId, String companyId, TokenUser tokenUser) {
        EmpSocRelatedDO empSocRelated = selectByEmpId(empId, tokenUser.getSiteId());
        if (ObjectUtils.isEmpty(empSocRelated)) {
            EmpSocRelatedAddDTO insert = new EmpSocRelatedAddDTO();
            insert.setEmpId(empId);
            insert.setCompanyId(companyId);
            insert.setSocState(0);
            insert.setMeState(0);
            insert.setPfState(0);
            save(insert, tokenUser);
        }
    }

    @Override
    public void clearedPlanIncreaseDate(EmpSocRelatedDO empSocRelatedDO, Integer type, TokenUser tokenUser) {
        List<Integer> typeList = Arrays.asList(1, 2, 3);
        if (typeList.contains(type)) {
            empSocRelatedDAO.clearedPlanIncreaseDate(empSocRelatedDO.getId(), type);
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    public void clearedPlanDecreaseDate(EmpSocRelatedDO empSocRelatedDO, Integer type, TokenUser tokenUser) {
        List<Integer> typeList = Arrays.asList(1, 2, 3);
        if (typeList.contains(type)) {
            empSocRelatedDAO.clearedPlanDecreaseDate(empSocRelatedDO.getId(), type);
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    public void checkDecreaseDate(EmpSocRelatedDO empSocRelatedDO, EmpSocPlanDO empSocPlanDO, EmpInfoDO empInfoDO) {
        List<Integer> checkList = Arrays.asList(EmpSocStatus.ATTRITION.getValue(),
                EmpSocStatus.WAIT_ATTRITION.getValue(), EmpSocStatus.STOP_SOC.getValue(), EmpSocStatus.NOT_SOC.getValue());
        Date planDecreaseDate = DateKit8.parseDate(empSocPlanDO.getYear() + "-" + empSocPlanDO.getMonth() + "-01");
        if (SOC_ITEM_TYPE.equals(empSocPlanDO.getType())) {
            Date socIncreaseDate = empSocRelatedDO.getSocIncreaseDate();
            Integer socState = empSocRelatedDO.getSocState();
            if (ObjectUtils.isEmpty(socIncreaseDate)) {
                throw new ParamException("员工" + empInfoDO.getName() + SOC_CACHE + "类型还未进行增员,不可进行减员反馈");
            } else {
                if (planDecreaseDate.before(socIncreaseDate)) {
                    throw new ParamException("员工" + empInfoDO.getName() + SOC_CACHE + "类型计划减员时间在增员时间之前不可进行减员标记");
                }
            }
            if (checkList.contains(socState)) {
                throw new ParamException("员工" + empInfoDO.getName() + "重复减员");
            }
        } else if (PF_ITEM_TYPE.equals(empSocPlanDO.getType())) {
            Date pfIncreaseDate = empSocRelatedDO.getPfIncreaseDate();
            Integer pfState = empSocRelatedDO.getPfState();
            if (ObjectUtils.isEmpty(pfIncreaseDate)) {
                throw new ParamException("员工" + empInfoDO.getName() + PF_CACHE + "类型还未进行增员,不可进行减员反馈");
            } else {
                if (planDecreaseDate.before(pfIncreaseDate)) {
                    throw new ParamException("员工" + empInfoDO.getName() + PF_CACHE + "类型计划减员时间在增员时间之前不可进行减员标记");
                }
            }
            if (checkList.contains(pfState)) {
                throw new ParamException("员工" + empInfoDO.getName() + "重复减员");
            }
        } else if (ME_ITEM_TYPE.equals(empSocPlanDO.getType())) {
            Date meIncreaseDate = empSocRelatedDO.getMeIncreaseDate();
            Integer meState = empSocRelatedDO.getMeState();
            if (ObjectUtils.isEmpty(meIncreaseDate)) {
                throw new ParamException("员工" + empInfoDO.getName() + ME_CACHE + "类型还未进行增员,不可进行减员反馈");
            } else {
                if (planDecreaseDate.before(meIncreaseDate)) {
                    throw new ParamException("员工" + empInfoDO.getName() + ME_CACHE + "类型计划减员时间在增员时间之前不可进行减员标记");
                }
            }
            if (checkList.contains(meState)) {
                throw new ParamException("员工" + empInfoDO.getName() + "重复减员");
            }
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    public void checkIncreaseDate(EmpSocRelatedDO empSocRelatedDO, EmpSocPlanDO empSocPlanDO, EmpInfoDO empInfoDO) {
        Date planIncreaseDate = DateKit8.parseDate(empSocPlanDO.getYear() + "-" + empSocPlanDO.getMonth() + "-01");
        List<Integer> checkList = Arrays.asList(EmpSocStatus.INCREMENT.getValue(),
                EmpSocStatus.WAIT_INCREMENT.getValue(), EmpSocStatus.NORMAL_SOC.getValue());
        if (SOC_ITEM_TYPE.equals(empSocPlanDO.getType())) {
            Date socStopDate = empSocRelatedDO.getSocStopDate();
            Integer socState = empSocRelatedDO.getSocState();
            if (!ObjectUtils.isEmpty(socStopDate) && planIncreaseDate.before(socStopDate)) {
                throw new ParamException("员工" + empInfoDO.getName() + SOC_CACHE + "类型计划增员时间在减员时间之前不可进行增员标记");
            }
            if (checkList.contains(socState)) {
                throw new ParamException("员工" + empInfoDO.getName() + "重复增员");
            }
        } else if (PF_ITEM_TYPE.equals(empSocPlanDO.getType())) {
            Date pfSealedDate = empSocRelatedDO.getPfSealedDate();
            Integer pfState = empSocRelatedDO.getPfState();
            if (!ObjectUtils.isEmpty(pfSealedDate) && planIncreaseDate.before(pfSealedDate)) {
                throw new ParamException("员工" + empInfoDO.getName() + PF_CACHE + "类型计划增员时间在减员时间之前不可进行增员标记");
            }
            if (checkList.contains(pfState)) {
                throw new ParamException("员工" + empInfoDO.getName() + "重复增员");
            }
        } else if (ME_ITEM_TYPE.equals(empSocPlanDO.getType())) {
            Date meStopDate = empSocRelatedDO.getMeStopDate();
            Integer meState = empSocRelatedDO.getMeState();
            if (!ObjectUtils.isEmpty(meStopDate) && planIncreaseDate.before(meStopDate)) {
                throw new ParamException("员工" + empInfoDO.getName() + ME_CACHE + "类型计划增员时间在减员时间之前不可进行增员标记");
            }
            if (checkList.contains(meState)) {
                throw new ParamException("员工" + empInfoDO.getName() + "重复增员");
            }
        } else {
            throw new ParamException("参保方案类型错误");
        }
    }

    @Override
    public EmpImportSocRelatedDTO findEmpSocRelated(String empId, String companyId, TokenUser tokenUser) {
        EmpImportSocRelatedDTO result = new EmpImportSocRelatedDTO();
        result.setEmpId(empId);
        // 先判断起缴时间有没有导入过,因为起缴时间优先用导入的
        EmpSocRelatedDO empSocRelated = selectByEmpId(empId, tokenUser.getSiteId());
        if (empSocRelated != null) {
            String importJson = empSocRelated.getImportJson();
            JSONObject importJsonObject;
            if (StringUtils.isEmpty(importJson)) {
                importJsonObject = new JSONObject();
            } else {
                importJsonObject = JSON.parseObject(importJson);
            }
            String startPaymentDate = importJsonObject.getString("startPaymentDate");
            EmpSocInfoDO empSocInfo = empSocInfoService.getEmpSocInfoByEmpId(empId, companyId, tokenUser.getSiteId());
            if (StringUtils.isEmpty(startPaymentDate) && !ObjectUtils.isEmpty(empSocInfo)) {
                startPaymentDate = DateUtils.getYearMonthByDate(DateUtils.compareMin(empSocRelated.getSocIncreaseDate(),
                        empSocRelated.getMeIncreaseDate(), empSocRelated.getPfIncreaseDate()));
            }
            result.setStartPaymentDate(startPaymentDate);
            result.setSocAccount(empSocRelated.getSocAccount());
            result.setMeAccount(empSocRelated.getMeAccount());
            result.setPfAccount(empSocRelated.getPfAccount());
            // 剩下的优先显示最新一条参保记录的
            List<EmpImportSocItemRelatedDTO> itemList = new ArrayList<>();
            // 参保城市
            String insuredCity = "";
            String insuredCityName = "";
            // 如果最新一条参保记录是空的  全拿导入的显示
            if (ObjectUtils.isEmpty(empSocInfo)) {
                // 处于可编辑状态
                result.setTurnOnEditing(true);
                if (!StringUtils.isEmpty(importJson)) {
                    String itemListJson = importJsonObject.getString("itemList");
                    if (!StringUtils.isEmpty(itemListJson)) {
                        itemList = JSONObject.parseArray(itemListJson, EmpImportSocItemRelatedDTO.class);
                    }
                    insuredCity = importJsonObject.getString("insuredCity");
                    if (!StringUtils.isEmpty(insuredCity)) {
                        int index = insuredCity.indexOf("/");
                        AreaDO area;
                        if (-1 == index) {
                            area = adminProviderService.getAreaByName(insuredCity, null);
                        } else {
                            String[] splitArea = insuredCity.split("/");
                            area = adminProviderService.getAreaByName(
                                    splitArea[splitArea.length - 1].replace("省", "").replace("市", ""),
                                    splitArea[splitArea.length - 2].replace("省", "").replace("市", ""));
                        }
                        insuredCity = area.getId() + "";
                    } else {
                        insuredCity = "";
                    }
                }
            } else {
                // 不可编辑
                result.setTurnOnEditing(false);
                List<EmpSocItemDO> empSocItemList = empSocItemService.selectByEmpSocId(empSocInfo.getId(), tokenUser.getSiteId());
                SocProgDO socProgDO = socProgService.selectDOById(empSocInfo.getProgId(), tokenUser.getSiteId());
                if (!ObjectUtils.isEmpty(socProgDO)) {
                    insuredCityName = socProgDO.getSocCityName();
                    insuredCity = socProgDO.getSocCity();
                }
                if (!CollectionUtils.isEmpty(empSocItemList)) {
                    itemList = empSocItemList.stream().
                            map(empSocItem -> empSocItem.to(EmpImportSocItemRelatedDTO.class))
                            .collect(Collectors.toList());
                }
            }
            result.setInsuredCity(insuredCity);
            result.setItemList(itemList);
            result.setInsuredCityName(insuredCityName);
            return result;
        }
        return null;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void empImportSocDate(List<EmpInfoImportDTO> importSucList, List<EmpInfoDO> empInfoDOList, String companyId, List<DictItemDO> itemList, TokenUser tokenUser) {
        List<EmpSocRelatedDO> saveList = new ArrayList<>();
        List<String> itemNameList = itemList.stream().map(DictItemDO::getDictItemValue).collect(Collectors.toList());
        Map<String, String> itemTypeMap = itemList.stream()
                .collect(Collectors.toMap(DictItemDO::getDictItemValue, DictItemDO::getSubjectType));
        // 身份证-信息 Map
        Map<String, EmpInfoImportDTO> idCardMap = importSucList.parallelStream()
                .collect(Collectors.toMap(EmpInfoImportDTO::getIdCard, v -> v));

        for (EmpInfoDO empInfoDO : empInfoDOList) {
            // 拿到导入的这个人的Excel信息
            EmpInfoImportDTO infoImportDTO = idCardMap.get(empInfoDO.getIdCard());
            Map<String, String> importMap = infoImportDTO.getAllMap();
            // 初始化一个员工社保相关信息对象
            EmpSocRelatedDO insert = new EmpSocRelatedDO();
            insert.setEmpId(empInfoDO.getId());
            insert.setCompanyId(companyId);
            insert.setSocState(0);
            insert.setMeState(0);
            insert.setPfState(0);
            insert.setSocAccount(importMap.get("社保账号"));
            insert.setMeAccount(importMap.get("医保账号"));
            insert.setPfAccount(importMap.get("公积金账号"));
            EmpImportSocRelatedDTO importData = initImportJsonByExcel(itemNameList, itemTypeMap, importMap);
            insert.setImportJson(JSONObject.toJSONString(importData));
            insert.setSiteId(tokenUser.getSiteId());
            insert.preInsert(tokenUser.getUserId());
            saveList.add(insert);
        }
        if (!CollectionUtils.isEmpty(saveList)) {
            empSocRelatedDAO.insertListAndSetId(saveList);
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void empUpdateSocDate(EmpImportSocRelatedDTO updateDTO, TokenUser tokenUser) {
        EmpSocRelatedDO empSocRelatedDO = selectByEmpId(updateDTO.getEmpId(), tokenUser.getSiteId());
        empSocRelatedDO.setImportJson(JSONObject.toJSONString(updateDTO));
        updateByIdSelective(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    public EmpSocRelatedListVO empSocRelatedImportData(List<String> empList, TokenUser tokenUser) {
        EmpSocRelatedListVO result = new EmpSocRelatedListVO();
        // 外层 List 是每个人 内层 List 是每个人中对应的子项列表
        List<List<EmpImportSocItemRelatedDTO>> socItem = new ArrayList<>();
        List<List<EmpImportSocItemRelatedDTO>> meItem = new ArrayList<>();
        List<List<EmpImportSocItemRelatedDTO>> pfItem = new ArrayList<>();
        List<EmpSocRelatedDO> empSocRelatedList = selectByEmpIdList(empList, tokenUser.getSiteId());
        for (EmpSocRelatedDO empSocRelatedDO : empSocRelatedList) {
            String importJson = empSocRelatedDO.getImportJson();
            if (!StringUtils.isEmpty(importJson)) {
                EmpImportSocRelatedDTO empImportSocRelatedDTO = JSONObject
                        .parseObject(importJson, EmpImportSocRelatedDTO.class);
                List<EmpImportSocItemRelatedDTO> itemList = empImportSocRelatedDTO.getItemList();
                if (!CollectionUtils.isEmpty(itemList)) {
                    socItem.add(itemList.stream().
                            filter(item -> SOC_ITEM_TYPE.equals(item.getItemType()) &&
                                    !StringUtils.isEmpty(item.getCardinalityDefault())).collect(Collectors.toList()));
                    meItem.add(itemList.stream().
                            filter(item -> ME_ITEM_TYPE.equals(item.getItemType()) &&
                                    !StringUtils.isEmpty(item.getCardinalityDefault())).collect(Collectors.toList()));
                    pfItem.add(itemList.stream().
                            filter(item -> PF_ITEM_TYPE.equals(item.getItemType()) &&
                                    !StringUtils.isEmpty(item.getCardinalityDefault())).collect(Collectors.toList()));
                }
            } else {
                return result;
            }
        }
        increaseCompareItem(socItem, empList.size(), result, SOC_ITEM_TYPE);
        increaseCompareItem(meItem, empList.size(), result, ME_ITEM_TYPE);
        increaseCompareItem(pfItem, empList.size(), result, PF_ITEM_TYPE);
        return result;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer deleteByEmpId(String empId, TokenUser tokenUser) {
        Example example = new Example(EmpSocRelatedDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("empId", empId)
                .andEqualTo("siteId", tokenUser.getSiteId());
        EmpSocRelatedDO empSocRelatedDO = empSocRelatedDAO.selectOneByExample(example);
        if (!ObjectUtils.isEmpty(empSocRelatedDO)) {
            return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), empSocRelatedDO.getId());
        }
        return null;
    }

    @Override
    public Boolean checkEmpCanBeDeleted(String empId, TokenUser tokenUser) {
        EmpSocRelatedDO empSocRelatedDO = selectByEmpId(empId, tokenUser.getSiteId());
        if (EmpSocStatus.INCREMENT.getValue().equals(empSocRelatedDO.getSocState()) ||
                EmpSocStatus.NORMAL_SOC.getValue().equals(empSocRelatedDO.getSocState())) {
            return false;
        }
        if (EmpSocStatus.INCREMENT.getValue().equals(empSocRelatedDO.getMeState()) ||
                EmpSocStatus.NORMAL_SOC.getValue().equals(empSocRelatedDO.getMeState())) {
            return false;
        }
        return !EmpSocStatus.INCREMENT.getValue().equals(empSocRelatedDO.getPfState()) &&
                !EmpSocStatus.NORMAL_SOC.getValue().equals(empSocRelatedDO.getPfState());
    }

    @Override
    @Async
    public void asyncUpdateRelated(List<EmpSocRelatedDO> updateList) {
        for (EmpSocRelatedDO empSocRelated : updateList) {
            updateByIdSelective(empSocRelated);
        }
    }

    @Override
    public void setAccountByScheme(Integer type, EmpSocRelatedDO empSocRelated, SocProgDO socScheme) {
        if (SOC_ITEM_TYPE.equals(type)) {
            empSocRelated.setSocAccount(StringUtils.isEmpty(socScheme.getSocAccount()) ? "" : socScheme.getSocAccount());
        } else if (ME_ITEM_TYPE.equals(type)) {
            empSocRelated.setMeAccount(StringUtils.isEmpty(socScheme.getMeAccount()) ? "" : socScheme.getMeAccount());
        } else if (PF_ITEM_TYPE.equals(type)) {
            empSocRelated.setPfAccount(StringUtils.isEmpty(socScheme.getPfAccount()) ? "" : socScheme.getPfAccount());
        }
    }

    @Override
    public void updateDict(DictItemDO dictItem, DictItemUpdateDTO update, TokenUser tokenUser) {
        EmpSocRelatedDO empSocRelated = new EmpSocRelatedDO();
        Example example = new Example(EmpSocRelatedDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        if ("1220".equals(dictItem.getDictCode())) {
            example.and().andEqualTo("socAccount", dictItem.getDictItemValue());
            empSocRelated.setSocAccount(update.getDictItemValue());
        } else if ("1221".equals(dictItem.getDictCode())) {
            example.and().andEqualTo("meAccount", dictItem.getDictItemValue());
            empSocRelated.setMeAccount(update.getDictItemValue());
        } else if ("1222".equals(dictItem.getDictCode())) {
            example.and().andEqualTo("pfAccount", dictItem.getDictItemValue());
            empSocRelated.setPfAccount(update.getDictItemValue());
        } else {
            return;
        }
        empSocRelatedDAO.updateByExampleSelective(empSocRelated, example);
    }

    @Override
    public Integer selectDict(DictItemDO dictItem, TokenUser tokenUser) {
        Example example = new Example(EmpSocRelatedDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId());
        if ("1220".equals(dictItem.getDictCode())) {
            example.and().andEqualTo("socAccount", dictItem.getDictItemValue());
        } else if ("1221".equals(dictItem.getDictCode())) {
            example.and().andEqualTo("meAccount", dictItem.getDictItemValue());
        } else if ("1222".equals(dictItem.getDictCode())) {
            example.and().andEqualTo("pfAccount", dictItem.getDictItemValue());
        } else {
            return 0;
        }
        return empSocRelatedDAO.selectCountByExample(example);
    }

    /**
     * 增员的时候校验增援人员的导入项
     */
    private void increaseCompareItem(List<List<EmpImportSocItemRelatedDTO>> itemEmpList, Integer empCount,
                                     EmpSocRelatedListVO result, Integer itemType) {
        if (itemEmpList.size() != 0 && itemEmpList.size() != empCount) {
            checkNull(itemType, result);
        } else {
            // 拿到所有人的 该项 的数目
            List<Integer> socItemCountList = itemEmpList.stream().map(List::size).distinct().collect(Collectors.toList());
            // 子项数目不同 或者 相同 但是都是0
            if (socItemCountList.size() > 1 || (socItemCountList.size() == 1 && socItemCountList.get(0).equals(0))) {
                checkNull(itemType, result);
            } else {
                Map<String, String> itemMap = new HashMap<>(8);
                for (int i = 0; i < itemEmpList.size(); i++) {
                    List<EmpImportSocItemRelatedDTO> itemRelatedList = itemEmpList.get(i);
                    for (EmpImportSocItemRelatedDTO itemList : itemRelatedList) {
                        // 把第一个人的子项基数给存起来,后面每一个人和第一个人做比较
                        if (i == 0) {
                            itemMap.put(itemList.getItemName(), itemList.getCardinalityDefault());
                            continue;
                        }
                        String cardinalityDefault = itemMap.get(itemList.getItemName());
                        if (StringUtils.isEmpty(cardinalityDefault) ||
                                !cardinalityDefault.equals(itemList.getCardinalityDefault())) {
                            checkNull(itemType, result);
                            return;
                        }
                    }
                }
                if (SOC_ITEM_TYPE.equals(itemType) && ObjectUtils.isEmpty(result.getSocImport())) {
                    result.setSocImport(itemMap);
                } else if (ME_ITEM_TYPE.equals(itemType) && ObjectUtils.isEmpty(result.getMeImport())) {
                    result.setMeImport(itemMap);
                } else if (PF_ITEM_TYPE.equals(itemType) && ObjectUtils.isEmpty(result.getPfImport())) {
                    result.setPfImport(itemMap);
                }
            }
        }
    }


    private void checkNull(Integer itemType, EmpSocRelatedListVO result) {
        if (SOC_ITEM_TYPE.equals(itemType)) {
            result.setSocImport(new HashMap<>(8));
        } else if (ME_ITEM_TYPE.equals(itemType)) {
            result.setMeImport(new HashMap<>(8));
        } else {
            result.setPfImport(new HashMap<>(8));
        }
    }

    /**
     * 根据Excel的内容填充出员工社保信息实体中的importJson字段
     */
    private EmpImportSocRelatedDTO initImportJsonByExcel(List<String> itemNameList, Map<String, String> itemTypeMap,
                                                         Map<String, String> importMap) {
        // 起缴时间,参保城市
        String startPaymentDate = importMap.get(START_PAYMENT_DATE);
        String insuredCity = importMap.get(INSURED_CITY);
        // 校验导入的数据是否能和这个公司下的社保子项名称匹配到,匹配到就保存
        List<EmpImportSocItemRelatedDTO> itemList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(itemNameList)) {
            for (String itemName : itemNameList) {
                String itemCardinality = importMap.get(itemName);
                if (!StringUtils.isEmpty(itemCardinality)) {
                    EmpImportSocItemRelatedDTO item = new EmpImportSocItemRelatedDTO();
                    Integer itemType = Integer.parseInt(itemTypeMap.get(itemName));
                    item.setItemName(itemName);
                    item.setItemType(itemType);
                    item.setCardinalityDefault(itemCardinality);
                    itemList.add(item);
                }
            }
        }
        EmpImportSocRelatedDTO importData = new EmpImportSocRelatedDTO();
        if (!CollectionUtils.isEmpty(itemList)) {
            importData.setItemList(itemList);
        } else {
            // 如果这个人一个参保项都没有,给他搞一套默认的五险一金
            importData.setItemList(initInsurance(itemList));
        }
        if (!StringUtils.isEmpty(startPaymentDate)) {
            importData.setStartPaymentDate(startPaymentDate);
        }
        if (!StringUtils.isEmpty(insuredCity)) {
            importData.setInsuredCity(insuredCity);
        }
        return importData;
    }

    /**
     * 如果一个人在花名册导入的时候一个参保项都没有,给他搞一套默认的五险一金
     */
    private List<EmpImportSocItemRelatedDTO> initInsurance(List<EmpImportSocItemRelatedDTO> itemList) {
        List<String> insuranceList = Arrays.asList(ENDOWMENT_INSURANCE, UNEMPLOYMENT_INSURANCE,
                EMPLOYMENT_INJURY_INSURANCE, MEDICAL_INSURANCE, MATERNITY_INSURANCE, PROVIDENT_FUND);
        for (String insurance : insuranceList) {
            EmpImportSocItemRelatedDTO item = new EmpImportSocItemRelatedDTO();
            Integer itemType = empSocItemService.getTypeByItemName(insurance);
            item.setItemName(insurance);
            item.setItemType(itemType);
            itemList.add(item);
        }
        return itemList;
    }

    /**
     * 根据查询参数，构建example
     *
     * @param empSocRelatedQuery 查询参数
     * @param siteId             所属站点id
     * @return example
     */
    private Example buildExample(EmpSocRelatedQuery empSocRelatedQuery, String siteId) {
        Example example = new Example(EmpSocRelatedDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (empSocRelatedQuery.getCompanyId() != null) {
            example.and().andEqualTo("companyId", empSocRelatedQuery.getCompanyId());
        }
        // 排序
        ExampleKit.setExampleOrder(example, empSocRelatedQuery.getOrders());
        return example;
    }
}




